class CrcUtils {
  CrcUtils._();

  static int CRC8(List<int> source, int offset, int length) {
    int wCRCin = 0x00;
    int wCPoly = 0x07;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      for (int j = 0; j < 8; j++) {
        bool bit = ((source[i] >> (7 - j) & 1) == 1);
        bool c07 = ((wCRCin >> 7 & 1) == 1);
        wCRCin <<= 1;
        if (c07 ^ bit) wCRCin ^= wCPoly;
      }
    }
    wCRCin &= 0xFF;
    return wCRCin ^= 0x00;
  }

  static int CRC8_DARC(List<int> source, int offset, int length) {
    int wCRCin = 0x00;
    int wCPoly = 0x9C;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      wCRCin ^= (source[i] & 0xFF);
      for (int j = 0; j < 8; j++) {
        if ((wCRCin & 0x01) != 0) {
          wCRCin >>= 1;
          wCRCin ^= wCPoly;
        } else {
          wCRCin >>= 1;
        }
      }
    }
    return wCRCin ^= 0x00;
  }

  static int CRC8_ITU(List<int> source, int offset, int length) {
    int wCRCin = 0x00;
    int wCPoly = 0x07;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      for (int j = 0; j < 8; j++) {
        bool bit = ((source[i] >> (7 - j) & 1) == 1);
        bool c07 = ((wCRCin >> 7 & 1) == 1);
        wCRCin <<= 1;
        if (c07 ^ bit) wCRCin ^= wCPoly;
      }
    }
    wCRCin &= 0xFF;
    return wCRCin ^= 0x55;
  }

  static int CRC8_MAXIM(List<int> source, int offset, int length) {
    int wCRCin = 0x00;
    int wCPoly = 0x8C;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      wCRCin ^= (source[i] & 0xFF);
      for (int j = 0; j < 8; j++) {
        if ((wCRCin & 0x01) != 0) {
          wCRCin >>= 1;
          wCRCin ^= wCPoly;
        } else {
          wCRCin >>= 1;
        }
      }
    }
    return wCRCin ^= 0x00;
  }

  static int CRC8_ROHC(List<int> source, int offset, int length) {
    int wCRCin = 0xFF;
    int wCPoly = 0xE0;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      wCRCin ^= (source[i] & 0xFF);
      for (int j = 0; j < 8; j++) {
        if ((wCRCin & 0x01) != 0) {
          wCRCin >>= 1;
          wCRCin ^= wCPoly;
        } else {
          wCRCin >>= 1;
        }
      }
    }
    return wCRCin ^= 0x00;
  }

  static int CRC16_IBM(List<int> source, int offset, int length) {
    int wCRCin = 0x0000;
    int wCPoly = 0xA001;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      wCRCin ^= (source[i] & 0x00FF);
      for (int j = 0; j < 8; j++) {
        if ((wCRCin & 0x0001) != 0) {
          wCRCin >>= 1;
          wCRCin ^= wCPoly;
        } else {
          wCRCin >>= 1;
        }
      }
    }
    return wCRCin ^= 0x0000;
  }

  static int CRC16_CCITT(List<int> source, int offset, int length) {
    int wCRCin = 0x0000;
    int wCPoly = 0x8408;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      wCRCin ^= (source[i] & 0x00FF);
      for (int j = 0; j < 8; j++) {
        if ((wCRCin & 0x0001) != 0) {
          wCRCin >>= 1;
          wCRCin ^= wCPoly;
        } else {
          wCRCin >>= 1;
        }
      }
    }
    return wCRCin ^= 0x0000;
  }

  static int CRC16_CCITT_FALSE(List<int> source, int offset) {
    int wCRCin = 0xFFFF;
    int wCPoly = 0x1021;
    for (int i = offset, cnt = offset + source.length; i < cnt; i++) {
      for (int j = 0; j < 8; j++) {
        bool bit = ((source[i] >> (7 - j) & 1) == 1);
        bool c15 = ((wCRCin >> 15 & 1) == 1);
        wCRCin <<= 1;
        if (c15 ^ bit) wCRCin ^= wCPoly;
      }
    }
    wCRCin &= 0xFFFF;
    return wCRCin ^= 0x0000;
  }

  static int CRC16_DECT_R(List<int> source, int offset, int length) {
    int wCRCin = 0x0000;
    int wCPoly = 0x0589;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      for (int j = 0; j < 8; j++) {
        bool bit = ((source[i] >> (7 - j) & 1) == 1);
        bool c15 = ((wCRCin >> 15 & 1) == 1);
        wCRCin <<= 1;
        if (c15 ^ bit) wCRCin ^= wCPoly;
      }
    }
    wCRCin &= 0xFFFF;
    return wCRCin ^= 0x0001;
  }

  static int CRC16_DECT_X(List<int> source, int offset, int length) {
    int wCRCin = 0x0000;
    int wCPoly = 0x0589;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      for (int j = 0; j < 8; j++) {
        bool bit = ((source[i] >> (7 - j) & 1) == 1);
        bool c15 = ((wCRCin >> 15 & 1) == 1);
        wCRCin <<= 1;
        if (c15 ^ bit) wCRCin ^= wCPoly;
      }
    }
    wCRCin &= 0xFFFF;
    return wCRCin ^= 0x0000;
  }

  static int CRC16_DNP(List<int> source, int offset, int length) {
    int wCRCin = 0x0000;
    int wCPoly = 0xA6BC;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      wCRCin ^= (source[i] & 0x00FF);
      for (int j = 0; j < 8; j++) {
        if ((wCRCin & 0x0001) != 0) {
          wCRCin >>= 1;
          wCRCin ^= wCPoly;
        } else {
          wCRCin >>= 1;
        }
      }
    }
    return wCRCin ^= 0xFFFF;
  }

  static int CRC16_GENIBUS(List<int> source, int offset, int length) {
    int wCRCin = 0xFFFF;
    int wCPoly = 0x1021;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      for (int j = 0; j < 8; j++) {
        bool bit = ((source[i] >> (7 - j) & 1) == 1);
        bool c15 = ((wCRCin >> 15 & 1) == 1);
        wCRCin <<= 1;
        if (c15 ^ bit) wCRCin ^= wCPoly;
      }
    }
    wCRCin &= 0xFFFF;
    return wCRCin ^= 0xFFFF;
  }

  static int CRC16_MAXIM(List<int> source, int offset, int length) {
    int wCRCin = 0x0000;
    int wCPoly = 0xA001;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      wCRCin ^= (source[i] & 0x00FF);
      for (int j = 0; j < 8; j++) {
        if ((wCRCin & 0x0001) != 0) {
          wCRCin >>= 1;
          wCRCin ^= wCPoly;
        } else {
          wCRCin >>= 1;
        }
      }
    }
    return wCRCin ^= 0xFFFF;
  }

  static int CRC16_MODBUS(List<int> source, int offset, int length) {
    int wCRCin = 0xFFFF;
    int wCPoly = 0xA001;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      wCRCin ^= (source[i] & 0x00FF);
      for (int j = 0; j < 8; j++) {
        if ((wCRCin & 0x0001) != 0) {
          wCRCin >>= 1;
          wCRCin ^= wCPoly;
        } else {
          wCRCin >>= 1;
        }
      }
    }
    return wCRCin ^= 0x0000;
  }

  static int CRC16_USB(List<int> source, int offset, int length) {
    int wCRCin = 0xFFFF;
    int wCPoly = 0xA001;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      wCRCin ^= (source[i] & 0x00FF);
      for (int j = 0; j < 8; j++) {
        if ((wCRCin & 0x0001) != 0) {
          wCRCin >>= 1;
          wCRCin ^= wCPoly;
        } else {
          wCRCin >>= 1;
        }
      }
    }
    return wCRCin ^= 0xFFFF;
  }

  static int CRC16_X25(List<int> source, int offset, int length) {
    int wCRCin = 0xFFFF;
    int wCPoly = 0x8408;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      wCRCin ^= (source[i] & 0x00FF);
      for (int j = 0; j < 8; j++) {
        if ((wCRCin & 0x0001) != 0) {
          wCRCin >>= 1;
          wCRCin ^= wCPoly;
        } else {
          wCRCin >>= 1;
        }
      }
    }
    return wCRCin ^= 0xFFFF;
  }

  static int CRC16_XMODEM(List<int> source, int offset, int length) {
    int wCRCin = 0x0000;
    int wCPoly = 0x1021;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      for (int j = 0; j < 8; j++) {
        bool bit = ((source[i] >> (7 - j) & 1) == 1);
        bool c15 = ((wCRCin >> 15 & 1) == 1);
        wCRCin <<= 1;
        if (c15 ^ bit) wCRCin ^= wCPoly;
      }
    }
    wCRCin &= 0xFFFF;
    return wCRCin ^= 0x0000;
  }

  static int CRC32(List<int> source, int offset, int length) {
    int wCRCin = 0xFFFFFFFF;
    int wCPoly = 0xEDB88320;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      wCRCin ^= (source[i] & 0x000000FF);
      for (int j = 0; j < 8; j++) {
        if ((wCRCin & 0x00000001) != 0) {
          wCRCin >>= 1;
          wCRCin ^= wCPoly;
        } else {
          wCRCin >>= 1;
        }
      }
    }
    return (wCRCin ^= 0xFFFFFFFF).toSigned(32);
  }

  static int CRC32_B(List<int> source, int offset, int length) {
    int wCRCin = 0xFFFFFFFF;
    int wCPoly = 0x04C11DB7;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      for (int j = 0; j < 8; j++) {
        bool bit = ((source[i] >> (7 - j) & 1) == 1);
        bool c31 = ((wCRCin >> 31 & 1) == 1);
        wCRCin <<= 1;
        if (c31 ^ bit) wCRCin ^= wCPoly;
      }
    }
    wCRCin &= 0xFFFFFFFF;
    return (wCRCin ^= 0xFFFFFFFF).toSigned(32);
  }

  static int CRC32_C(List<int> source, int offset, int length) {
    int wCRCin = 0xFFFFFFFF;
    int wCPoly = 0x82F63B78;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      wCRCin ^= (source[i] & 0x000000FF);
      for (int j = 0; j < 8; j++) {
        if ((wCRCin & 0x00000001) != 0) {
          wCRCin >>= 1;
          wCRCin ^= wCPoly;
        } else {
          wCRCin >>= 1;
        }
      }
    }
    return (wCRCin ^= 0xFFFFFFFF).toSigned(32);
  }

  static int CRC32_D(List<int> source, int offset, int length) {
    int wCRCin = 0xFFFFFFFF;
    int wCPoly = 0xD419CC15;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      wCRCin ^= (source[i] & 0x000000FF);
      for (int j = 0; j < 8; j++) {
        if ((wCRCin & 0x00000001) != 0) {
          wCRCin >>= 1;
          wCRCin ^= wCPoly;
        } else {
          wCRCin >>= 1;
        }
      }
    }
    return (wCRCin ^= 0xFFFFFFFF).toSigned(32);
  }

  static int CRC32_MPEG_2(List<int> source, int offset, int length) {
    int wCRCin = 0xFFFFFFFF;
    int wCPoly = 0x04C11DB7;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      for (int j = 0; j < 8; j++) {
        bool bit = ((source[i] >> (7 - j) & 1) == 1);
        bool c31 = ((wCRCin >> 31 & 1) == 1);
        wCRCin <<= 1;
        if (c31 ^ bit) wCRCin ^= wCPoly;
      }
    }
    wCRCin &= 0xFFFFFFFF;
    return (wCRCin ^= 0x00000000).toSigned(32);
  }

  static int CRC32_POSIX(List<int> source, int offset, int length) {
    int wCRCin = 0x00000000;
    int wCPoly = 0x04C11DB7;
    for (int i = offset, cnt = offset + length; i < cnt; i++) {
      for (int j = 0; j < 8; j++) {
        bool bit = ((source[i] >> (7 - j) & 1) == 1);
        bool c31 = ((wCRCin >> 31 & 1) == 1);
        wCRCin <<= 1;
        if (c31 ^ bit) {
          wCRCin ^= wCPoly;
        }
      }
    }
    wCRCin &= 0xFFFFFFFF;
    return (wCRCin ^= 0xFFFFFFFF).toSigned(32);
  }
}
